#!/usr/bin/perl

use DBI;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use strict;
use IO::File;

package KeyParse;

use XML::libxml;
use XML::Writer;

my $rootNode = {};                         # allocate new node
$rootNode->{VALUE}  = "0";
$rootNode->{ORG_ID}  = "-1";
$rootNode->{PARENT_ID}  = "-1";
$rootNode->{DESC}  = "Root Node";
$rootNode->{LEFT}   = undef;
$rootNode->{RIGHT}  = undef;

my $cgi = new CGI; 
#print $cgi->header(); 
my $filename =$cgi->param('filename'); 
#print "The input file $filename";

my $outputdir =$cgi->param('output');
#print "The outputdir is $outputdir";
my $outputfile=">".$outputdir."keyconversion.xml";
#print "The output file $outputfile";
my $errorfile=">>".$outputdir."error.txt";
my $output = IO::File->new($outputfile);
#if(defined $output)
#{
print"<br><br> Generating XML....<br>";

my $writer = XML::Writer->new(OUTPUT => $output, DATA_MODE => 1,DATA_INDENT => 2);
#}

my $currentNode=$rootNode;
my $organism_count = 1;
# File is assumed to be valid
my $fileValidate = 1;
my $InsertRightNode = 1;
# Perl trim function to remove whitespace from the start and end of the string
sub trim($)
{
	my $string = shift;
	$string =~ s/^\s+//;
	$string =~ s/\s+$//;
	return $string;
}

#Insert a node in Binary Tree
sub InsertNode($$)
{
	our($ParentNode, $record) = @_;
	
        my $tree = {};                         # allocate new node
        $tree->{VALUE}  = $record->{"NODE"};
        $tree->{ORG_ID}  = $record->{"ORG_ID"};
        $tree->{PARENT_ID}  = $record->{"PARENT_ID"};
	$tree->{PRIME}  = $record->{"PRIME"};
	$tree->{DESC}  = $record->{"DESC"};
        $tree->{LEFT}   = undef;
        $tree->{RIGHT}  = undef;
        $_[0] = $tree;              # $_[0] is reference param!
	$currentNode = $tree;
}

#Search a non-prime number in Binary Tree
sub search
{
    my($tree, $value, $recordref) = @_;
    return unless $tree->{LEFT};
    #non-prime number can only be left child
    if ($tree->{LEFT}->{VALUE} == $value) {

    if($tree->{RIGHT}) {
	$fileValidate = 0;
        open (ERRORFILE, $errorfile);
	print ERRORFILE "<br>Invalid Input file - $tree->{LEFT}->{VALUE}' prime is already present\nPlease upload the file in correct format<br>";	
        close (ERRORFILE);
        exit;
    }

	$InsertRightNode = 1;
	#found parent, insert prime node at right
	#print("\nInsert Prime Node $value' as right child of Node $tree->{VALUE}\n");
        $recordref->{PARENT_ID} = $tree->{VALUE}.$tree->{PRIME}; 
	InsertNode($tree->{RIGHT}, $recordref );
        return;
    }
    search($tree->{LEFT}, $value, $recordref);
    search($tree->{RIGHT}, $value, $recordref);    
}

# recurse on left child, 
# then show current value, 
# then recurse on right child.
sub search_node
{
    my($tree, $value) = @_;
    return unless $tree;
    print("Find $value");
    if($tree->{VALUE} != -1 ){
        #print $tree->{VALUE}, " ";
        if($tree->{VALUE} == $value)
        {
        open (ERRORFILE, $errorfile);
	print ERRORFILE "<br>Invalid Input file - $value node is already present\nPlease upload the file in correct format<br>";	
        close (ERRORFILE);
        exit;
        }
    }
	search_node($tree->{LEFT}, $value);
    search_node($tree->{RIGHT}, $value);
}

# recurse on left child, 
# then show current value, 
# then recurse on right child.
sub pre_order
{
    my($tree) = @_;
    return unless $tree;
	if($tree->{VALUE} != -1 ){
    print $tree->{VALUE}, " ";
	}
	pre_order($tree->{LEFT});
    pre_order($tree->{RIGHT});
}

# show current value, 
# then recurse on left child, 
# then recurse on right child.
sub in_order
{
    my($tree) = @_;
    return unless $tree;
	in_order($tree->{LEFT});

	if($tree->{VALUE} != -1 && $tree->{VALUE} != 0 ){
		print $tree->{VALUE};
		print $tree->{PRIME}, " :";
		print $tree->{DESC}, " <br> ";
		
		print"<input name=\"userfile[]\" type=\"file\" /><br />";
	}
    in_order($tree->{RIGHT});
}


# recurse on left child, 
# then recurse on right child,
# then show current value. 
sub post_order {
    my($tree) = @_;
    return unless $tree;
    post_order($tree->{LEFT});
    post_order($tree->{RIGHT});
	if($tree->{VALUE} != -1 ){
		print $tree->{VALUE}, " ";
	}
}

sub post_order_organisms {
    my($tree) = @_;
    return unless $tree;
    post_order_organisms($tree->{LEFT});
    post_order_organisms($tree->{RIGHT});
    if($tree->{VALUE} == -1 ){
        if($writer)
        {
        $writer->startTag("organism");
        $writer->startTag("org_id");
        $writer->characters( "$tree->{ORG_ID}" );
        $writer->endTag('org_id');
        $writer->startTag('common_name');
        $writer->characters( "$tree->{DESC}" );
        $writer->endTag("common_name");
        $writer->endTag("organism");
        }
    }
}

sub post_order_nodes {
    my($tree) = @_;
    return unless $tree;
    post_order_nodes($tree->{LEFT});
    post_order_nodes($tree->{RIGHT});
    if($tree->{VALUE} != -1 ){
        if($writer)
        {
        $writer->startTag("Node");
        $writer->startTag("nodeID");
        my $nodeName;
        if($tree->{PRIME})
        {
            $nodeName = $tree->{VALUE}.$tree->{PRIME};
        }
        else
        {
            $nodeName = $tree->{VALUE};
        }
        $writer->characters( "$nodeName" );
        $writer->endTag('nodeID');
        $writer->startTag('parentID');
        $writer->characters( "$tree->{PARENT_ID}" );
        $writer->endTag("parentID");
        if(defined $tree->{RIGHT})
        {
            $writer->startTag("isLeafNode");
            $writer->characters( "no" );
            $writer->endTag('isLeafNode');
            $writer->startTag('leftChildID');
            $writer->characters( "$tree->{LEFT}->{VALUE}" );
            $writer->endTag("leftChildID");
            $writer->startTag("leftChildDescription");
            $writer->characters( "$tree->{LEFT}->{DESC}" );
            $writer->endTag('leftChildDescription');
            $writer->startTag('rightChildID');
            $writer->characters( "$tree->{RIGHT}->{VALUE}$tree->{RIGHT}->{PRIME}" );
            $writer->endTag("rightChildID");
            $writer->startTag("rightChildDescription");
            $writer->characters( "$tree->{RIGHT}->{DESC}" );
            $writer->endTag('rightChildDescription');
            $writer->emptyTag('organism_id');
        }
        else
        {
            $writer->startTag("isLeafNode");
            $writer->characters( "yes" );
            $writer->endTag('isLeafNode');
            $writer->emptyTag('leftChildID');
            $writer->emptyTag('leftChildDescription');
            $writer->emptyTag('rightChildID');
            $writer->emptyTag('rightChildDescription');
            $writer->startTag('organism_id');
            $writer->characters( "$tree->{LEFT}->{ORG_ID}" );
            $writer->endTag("organism_id");
        }

        $writer->endTag("Node");
        }
    }
}


sub generate_xml{
    my($tree) = @_;
    if(defined $output)
    {
        #geneate_header();
        $writer->xmlDecl("ISO-8859-1");
        $writer->startTag("Key_components");
        $writer->startTag("splash");
        $writer->startTag("software_authors");
        $writer->characters("Prajakta Rane");
        $writer->endTag("software_authors");
        $writer->endTag("splash");

        #generate_organisms();
        $writer->startTag("organisms");
        post_order_organisms($tree);
        $writer->endTag("organisms");
        #generate_nodes();
        $writer->startTag("nodes");
        post_order_nodes($tree);
        $writer->endTag("nodes");

        $writer->startTag("GlossaryItems");
        $writer->endTag("GlossaryItems");

        $writer->endTag("Key_components");


        $writer->end();
        $output->close;	
    }
print "<br>2<br>";

}

# validate input file
sub validate {
    my($tree) = @_;
    return unless $tree;
    #return unless $tree->{LEFT};
    unless($tree->{LEFT}){
 	$fileValidate = 0;
        open (ERRORFILE, $errorfile);
	print ERRORFILE "<br>Invalid Input file - $tree->{VALUE}' has no organism. Please upload the file in correct format<br>";	
        close (ERRORFILE);
        exit;       
    }

    if($tree->{LEFT}->{VALUE} == -1) {
	return;
    }
    unless($tree->{RIGHT}) {
	$fileValidate = 0;
        open (ERRORFILE, $errorfile);
	print ERRORFILE "<br>Invalid Input file - $tree->{LEFT}->{VALUE}' is not present<br>Please upload the file in correct format<br>";	
        close (ERRORFILE);
        exit;
    }
    if ($tree->{LEFT}->{VALUE} != $tree->{RIGHT}->{VALUE}) {
	$fileValidate = 0;
        open (ERRORFILE, $errorfile);
	print ERRORFILE "<br>Invalid Input file - Error for node $tree->{LEFT}->{VALUE}<br>";	
        close (ERRORFILE);
        exit;
    }
    validate($tree->{LEFT});
    validate($tree->{RIGHT});
}

#print "Content-Type:text/html \n\n";
#print "Hello World \n\n";
print "$filename\n";

my $path= $outputdir. $filename;
open (MYFILE, $path) or die $!;
#print $cgi->header();
my $first_line = 1; #define first line as true
my $total_nodes = 0;
my $total_organisms = 0;
my %organism_list = {};
while (<MYFILE>)
{
	my $str = $_;
	chomp($str);
	$str = trim($str);

	#check if a number is present
        if ($str)
        {
            #check if first line is valid non-prime node.
            if($first_line)
            {
                if($str !~ m/^([0-9]+)\.*(.*)/)
                {
                            $fileValidate = 0;
                            open (ERRORFILE, $errorfile);
                            print ERRORFILE "<br>Invalid Input File. First line should be non-prime node. Please upload file in correct format.<br>";	
                            close (ERRORFILE);
                            exit;
                }
                $first_line = 0;
            }

            if ($str =~ m/^([0-9]+)[']\.*(.*)/)
            {
                    my %record=
                    (
                            "NODE"=>trim($1),
                            "ORG_ID"=>"-1",
                            "PARENT_ID"=>$currentNode->{VALUE}.$currentNode->{PRIME},
                            "PRIME"=>"_",
                            "DESC"=>trim($2)
                    )
                    ;
                    #search parent for its non prime node
                    $InsertRightNode = 0;
                    search($rootNode, trim($1), \%record);
                    if( !$InsertRightNode)
                    {
                            $fileValidate = 0;
                            open (ERRORFILE, $errorfile);
                            print ERRORFILE "<br>Invalid Input File. Node $1 does not exist. Please upload file in correct format.<br>";	
                            close (ERRORFILE);
                            exit;
                    }
            }
            elsif ($str =~ m/^([0-9]+)\.*(.*)/) {
                    my %record =
                    (
                            "NODE"=>trim($1),
                            "ORG_ID"=>"-1",
                            "PARENT_ID"=>$currentNode->{VALUE}.$currentNode->{PRIME},
                            "PRIME"=>"",
                            "DESC"=>trim($2)
                    );		
                    #Insert on left
                    #print("Insert Node $1 as left child of Node $currentNode->{VALUE}\n");
                    # Search if node is already exist
                    search_node($rootNode, trim($1));
                    InsertNode($currentNode->{LEFT}, \%record );
                    $total_nodes++;
            }
            else {
                    #print "leaf is $str\n";
                    my %record =
                    (
                            "NODE"=>"-1",
                            "ORG_ID"=>"$organism_count",
                            "PARENT_ID"=>$currentNode->{VALUE}.$currentNode->{PRIME},
                            "PRIME"=>"",
                            "DESC"=>trim($str)
                    );
                    #print("Insert Organism as child of Node $currentNode->{VALUE}\n");
                    InsertNode($currentNode->{LEFT}, \%record );
                    $organism_count++;
                    $organism_list{"$total_organisms"} = \%record;
            }
        }
}# while (<MYFILE>) 
close (MYFILE);

validate($rootNode);

if( $fileValidate )
{
generate_xml($rootNode);
}